#ifndef Port_First
#define Port_First
#ifdef __GNUG__
#pragma interface
#endif

#include "Types.h"
#include "Object.h"
#include "Point.h"
#include "Rectangle.h"
#include "Metric.h"
#include "Font.h"
#include "Ink.h"
#include "Bitmap.h"
#include "Token.h"

class ImageCache;
class Picture;

extern const int MaxTextBatchCnt;

enum GrHints {
	eHintBatch,
	eHintUnbatch,
	eHintPostScript,
	eHintPic,
	eHintCacheStart,
	eHintCacheEnd,
	eHintWinErrorMsg,
	eHintWinStatusMsg,
	eHintWinBusy,
	eHintWinSetName,
	eHintEPSFStart,
	eHintEPSFEnd
};

enum GrLineCap {
	eDefaultCap,
	eStartArrow,
	eEndArrow
};

enum GrPolyType {
	ePolyDefault,
	ePolyBezier
};

enum GrCursor {
	eCrsNone,
	eCrsArrow,
	eCrsBoldArrow,
	eCrsCross,
	eCrsBoldCross,
	eCrsUpArrow,
	eCrsDownArrow,
	eCrsRightArrow,
	eCrsLeftArrow,
	eCrsHourglass,
	eCrsPen,
	eCrsMoveHand,
	eCrsHand,
	eCrsCrossHair,
	eCrsMoveStretch,
	eCrsIBeam,
	eCrsLeftRightArrow,
	eCrsUpDownArrow
};

class GrState {
public:
	Port *port;
	Rectangle clip;
	Point origin;
	float scalex, scaley;
public:
	GrState(Port *port= 0);
	~GrState();
	void Use() const
		{ }
};

//---- Port --------------------------------------------------------------------

class Port : public Object {
friend ImageCache;
friend GrState;
friend Bitmap;
friend Ink;
protected:
	static Port *port;

	static Port *tbport;
	static Ink *tbink;
	static Point tbpos, tblastpos;
	static Rectangle tbbbox;

	/* graphic state */
	Point origin;
	Rectangle cliprect;
	Ink *fillink;

	/* pen state */
	Point penpos;
	short pensize;
	Ink *penink;
	GrLineCap pencap;

	/* text state */
	Point textpos;
	Ink *textink;
	Font *textfont;

	/* other */
	Ink *lastink;
	bool ignore;
	bool hascolor;
	int depth;
	Point fso;

public:
	bool scale;
	float scalex, scaley;
	Font *sfont, *lastfdp;
		
protected:
	Port();

	bool Visible(Ink *ink, const Rectangle &r);
	void InstallInk(Ink *ink)
		{ lastink= ink; ink->SetInk(this); }

	//---- device dependent primitives
	virtual void DevClip(const Rectangle&);
	virtual bool DevScale(float sx, float sy);
	virtual void DevSetPattern(Bitmap*);
	virtual void DevSetColor(RGBColor*);
	virtual void DevSetOther(int);
	virtual void DevSetGrey(float);
	virtual void DevStrokeLine(int, const Rectangle&, GrLineCap, const Point&,
		const Point&);
	virtual void DevStrokeRect(int, const Rectangle&);
	virtual void DevFillRect(const Rectangle&);
	virtual void DevStrokeOval(int, const Rectangle&);
	virtual void DevFillOval(const Rectangle&);
	virtual void DevStrokeRRect(int, const Rectangle&, const Point&);
	virtual void DevFillRRect(const Rectangle&, const Point&);
	virtual void DevStrokeWedge(int, GrLineCap, const Rectangle&, int, int);
	virtual void DevFillWedge(const Rectangle&, int, int);
	virtual void DevStrokePolygon(const Rectangle&, Point*, int, GrPolyType t,
									int, GrLineCap);
	virtual void DevFillPolygon(const Rectangle&, Point*, int, GrPolyType t);
	virtual void DevShowBitmap(const Rectangle&, Bitmap*);
	virtual void DevShowPicture(const Rectangle&, Picture *pic);
	virtual void DevShowChar(Font*, const Point&, Rune, const Rectangle&);
	virtual void DevShowTextBatch(const Rectangle&, const Point&);
	virtual void DevGiveHint(int code, int len, void *vp);
	virtual GrCursor SetCursor(GrCursor c);
	virtual GrCursor SetWaitCursor(unsigned int d= 400, GrCursor c= eCrsHourglass);
	virtual GrCursor GetCursor();
	virtual bool DevImageCacheBegin(ImageCache *bb, const Rectangle &r);
	virtual void DevImageCacheEnd(ImageCache *bb);

	virtual void DevStrokeRect2(int, const Rectangle&);
	virtual void DevStrokeRRect2(int, const Rectangle&, const Point&);
	virtual void DevFillRRect2(const Rectangle&, const Point&);
	virtual void DevStrokeOval2(int, const Rectangle&);
	virtual void DevFillOval2(const Rectangle&);
	virtual void DevStrokeLine2(int, const Rectangle&, GrLineCap, const Point&,
				const Point&);
	virtual void DevStrokeWedge2(int, GrLineCap, const Rectangle&, int, int);
	virtual void DevFillWedge2(const Rectangle&, int, int);
	virtual void DevStrokePolygon2(const Rectangle&, Point*, int, GrPolyType,
				int, GrLineCap);
	virtual void DevFillPolygon2(const Rectangle&, Point*, int, GrPolyType);
	virtual Point DevDrawArrow(int, const Point&, const Point&);

public:

	MetaDef(Port);
	virtual ~Port();
	void PortInit();

	bool HasColor()
		{ return hascolor; }
	int GetDepth()
		{ return depth; }

	//---- clipping
	void Clip(const Rectangle &r);
	void ClipFurther(const Rectangle &r);
	const Rectangle &GetCliprect()
		{ return cliprect; }
	void Translate(const Point &p);
	const Point &GetOrigin()
		{ return origin; }
	void Scale(float x, float y);
	float GetXScale()
		{ return scalex; }
	float GetYScale()
		{ return scaley; }
	void InitClip();

	//---- Fill
	void SetNormal()
		{ fillink= gInkBlack; }
	void SetInk(Ink *p)
		{ fillink= p; }
	void SetColor(RGBColor*);
	void FillRect(Ink*, const Rectangle &r);
	void FillOval(Ink*, const Rectangle &r);
	void FillRRect(Ink*, const Rectangle &r, const Point &corner);
	void FillWedge(Ink*, const Rectangle &r, int, int);
	void FillPolygon(const Point &at, Ink*, Point*, int, GrPolyType);

	//---- Pen and Lines
	void SetPenNormal();
	void SetPenInk(Ink *p)
		{ penink= p; }
	Ink *GetPenInk()
		{ return penink; }
	void SetLineCap(GrLineCap lc)
		{ pencap= lc; }
	void SetPenSize(int w)
		{ pensize= w; }
	void Moveto(const Point &p)
		{ penpos= p; }
	void Moveby(const Point &p)
		{ penpos+= p; }

	void StrokeLine(Ink*, int, GrLineCap, const Point&, const Point&);
	void Line(const Point &p1, const Point &p2)
		{ StrokeLine(penink, pensize, pencap, p1, p2); }
	void PaintLine(Ink *ink, GrLineCap cap, const Point &p1, const Point &p2)
		{ StrokeLine(ink, pensize, cap, p1, p2); }
	void Lineto(const Point &p)
		{ StrokeLine(penink, pensize, pencap, penpos, p); penpos= p; }

	void StrokeRect(Ink*, int, const Rectangle &r);
	void StrokeOval(Ink*, int, const Rectangle &);
	void StrokeRRect(Ink*, int, const Rectangle &r, const Point &corner);
	void StrokeWedge(Ink*, int, GrLineCap, const Rectangle &r, int, int);
	void StrokePolygon(const Point &at, Ink*, Point*, int, GrPolyType, int, GrLineCap);

	//---- Text
	void SetTextNormal();
	void SetFamily(GrFont);
	void SetFont(Font *fd);
	Font *GetFont()
		{ return textfont; }
	void SetSize(int);
	void SetFace(GrFace);
	void SetTextInk(Ink *p)
		{ textink= p; }
	Ink *GetTextInk()
		{ return textink; }

	const Point &GetTextPos()
		{ return textpos; }
	void TextMoveto(const Point &p)
		{ textpos= p; }
	void TextMoveby(const Point &p)
		{ textpos+= p; }
	void TextHMoveby(int h)
		{ textpos.x+= h; }
	void TextVMoveby(int v)
		{ textpos.y+= v; }
		
	int ShowChar(Font *fdp, Ink *ink, const Point &pos, Rune c);
	void DrawChar(Rune c)
		{ textpos.x+= ShowChar(textfont, textink, textpos, c); }

	int ShowString(Font*, Ink*, const Point &pos, byte*, int);
	void DrawString(byte *text, int l)
		{ textpos.x+= ShowString(textfont, textink, textpos, text, l); }

	void flushtext();
	void FlushMyText()
		{ if (tbport == this) flushtext(); }
	static void FlushAnyText()
		{ if (tbport) tbport->flushtext(); }

	//---- misc
	void ShowBitmap(Ink*, const Rectangle &r, Bitmap*);
	void ShowPicture(const Rectangle &r, Picture*);
	void GiveHint(int code, int len, void *vp);

	//---- Port syntactic sugar
	friend void GrSetPort(Port *newport);
	friend Port *GrGetPort();

	//---- clipping
	friend void GrInitClip();
	friend void GrSetClip(const Rectangle &r);
	friend void GrClipFurther(const Rectangle &r);
	friend const Rectangle &GrGetClip();
	friend void GrTranslate(const Point &o);
	friend const Point &GrGetOrigin();
	friend void GrScale(float x, float y);
	friend float GrGetXScale();
	friend float GrGetYScale();

	//---- fill
	friend void GrSetInk(Ink *p);

	//---- pens
	friend void GrSetPenSize(int w);
	friend void GrSetLineCap(GrLineCap lc);
	friend void GrSetPenInk(Ink *p);
	friend Ink *GrGetPenInk();
	friend void GrSetPenNormal();

	//---- lines
	friend void GrMoveto(const Point &p);
	friend void GrLineto(const Point &p);
	friend void GrLine(const Point &p1, const Point &p2);
	friend void GrPaintLine(Ink *ink, int psz, GrLineCap cap, const Point &p1, const Point &p2);
	friend void GrStrokeLine(Ink *ink, GrLineCap cap, const Point &p1, const Point &p2);
	friend void GrInvertLine(const Point &p1, const Point &p2);
	friend void GrEraseLine(const Point &p1, const Point &p2);

	//---- rectangle
	friend void GrFillRect(const Rectangle &r);
	friend void GrStrokeRect(const Rectangle &r);
	friend void GrEraseRect(const Rectangle &r);
	friend void GrInvertRect(const Rectangle &r);
	friend void GrPaintRect(const Rectangle &r, Ink *ink);

	//---- round rectangles
	friend void GrStrokeRoundRect(const Rectangle &r, const Point &dia);
	friend void GrFillRoundRect(const Rectangle &r, const Point &dia);
	friend void GrEraseRoundRect(const Rectangle &r, const Point &dia);
	friend void GrInvertRoundRect(const Rectangle &r, const Point &dia);
	friend void GrPaintRoundRect(const Rectangle &r, const Point &dia,Ink *ink);

	//----- ovals
	friend void GrStrokeOval(const Rectangle &r);
	friend void GrFillOval(const Rectangle &r);
	friend void GrEraseOval(const Rectangle &r);
	friend void GrInvertOval(const Rectangle &r);
	friend void GrPaintOval(const Rectangle &r, Ink *ink);

	//----- wedges
	friend void GrStrokeWedge(const Rectangle &r, int s, int e);
	friend void GrFillWedge(const Rectangle &r, int s, int e);
	friend void GrEraseWedge(const Rectangle &r, int s, int e);
	friend void GrInvertWedge(const Rectangle &r, int s, int e);
	friend void GrPaintWedge(const Rectangle &r, int s, int e, Ink *ink);

	//---- bitmaps
	friend void GrShowBitMap(const Rectangle &r, Bitmap *bmp);
	friend void GrPaintBitMap(const Rectangle &r, Bitmap *bmp, Ink *ink);
	friend void GrInvertBitMap(const Rectangle &r, Bitmap *bmp);

	//--- Polygon
	friend void GrStrokePolygon(const Point &at, Point *pts, int npts, GrPolyType t);
	friend void GrFillPolygon(const Point &at, Point *pts, int npts, GrPolyType t);
	friend void GrErasePolygon(const Point &at, Point *pts, int npts, GrPolyType t);
	friend void GrInvertPolygon(const Point &at, Point *pts, int npts, GrPolyType t);
	friend void GrPaintPolygon(const Point &at, Ink *ink, Point *pts, int npts, GrPolyType t);

	//---- text
	friend void GrSetFont(Font *fd);
	friend Font *GrGetFont();
	friend void GrSetFamily(GrFont f);
	friend void GrSetSize(int s);
	friend void GrSetFace(GrFace f);
	friend void GrSetTextInk(Ink *tink);
	friend void GrSetTextNormal();
	friend Ink *GrGetTextInk();
	friend void GrTextMoveto(Point p);
	friend void GrTextAdvance(int h);
	friend const Point &GrGetTextPos();

	friend int GrShowChar(Font *fdp, Ink *ink, const Point &pos, Rune c);
	friend void GrDrawChar(Rune c);
	friend int GrShowString(Font *fd, Ink *ink, const Point &pos, byte *text, int l= -1);
	friend void GrDrawString(byte *s, int l= -1);

	//---- pictures
	friend void GrShowPicture(const Rectangle &r, Picture *pic);

	//---- cursor
	friend GrCursor GrSetCursor(GrCursor c);
	friend GrCursor GrGetCursor();
	friend GrCursor GrSetWaitCursor(unsigned int d= 400, GrCursor c= eCrsHourglass);

	//---- misc
	friend void GrGiveHint(int n, int l= 0, void *v= 0);
	friend bool GrHasColor();
};

inline void GrSetPort(Port *newport)
	{ Port::port= newport; }
inline Port *GrGetPort()
	{ return Port::port; }
inline void GrInitClip()
	{ Port::port->InitClip(); }
inline void GrSetClip(const Rectangle &r)
	{ Port::port->Clip(r); }
inline void GrClipFurther(const Rectangle &r)
	{ Port::port->ClipFurther(r); }
inline const Rectangle &GrGetClip()
	{ return Port::port->GetCliprect(); }
inline void GrTranslate(const Point &o)
	{ Port::port->Translate(o); }
inline const Point &GrGetOrigin()
	{ return Port::port->GetOrigin(); }
inline void GrScale(float x, float y)
	{ Port::port->Scale(x, y); }
inline float GrGetXScale()
	{ return Port::port->GetXScale(); }
inline float GrGetYScale()
	{ return Port::port->GetYScale(); }
inline void GrSetInk(Ink *p)
	{ Port::port->SetInk(p); }
inline void GrSetPenSize(int w)
	{ Port::port->SetPenSize(w); }
inline void GrSetLineCap(GrLineCap lc)
	{ Port::port->SetLineCap(lc); }
inline void GrSetPenInk(Ink *p)
	{ Port::port->SetPenInk(p); }
inline Ink *GrGetPenInk()
	{ return Port::port->GetPenInk(); }
inline void GrSetPenNormal()
	{ Port::port->SetPenNormal(); }
inline void GrMoveto(const Point &p)
	{ Port::port->Moveto(p); }
inline void GrLineto(const Point &p)
	{ Port::port->Lineto(p); }
inline void GrLine(const Point &p1, const Point &p2)
	{ Port::port->StrokeLine(Port::port->penink, Port::port->pensize,
				Port::port->pencap, p1, p2); }
inline void GrPaintLine(Ink *ink, int psz, GrLineCap cap, const Point &p1, const Point &p2)
	{ Port::port->StrokeLine(ink, psz, cap, p1, p2); }
inline void GrStrokeLine(Ink *ink, GrLineCap cap, const Point &p1, const Point &p2)
	{ Port::port->StrokeLine(ink, Port::port->pensize, cap, p1, p2); }
inline void GrInvertLine(const Point &p1, const Point &p2)
	{ Port::port->StrokeLine(gInkXor, Port::port->pensize, Port::port->pencap, p1, p2); }
inline void GrEraseLine(const Point &p1, const Point &p2)
	{ Port::port->StrokeLine(gInkWhite, Port::port->pensize, Port::port->pencap, p1, p2); }
inline void GrFillRect(const Rectangle &r)
	{ Port::port->FillRect(Port::port->fillink, r); }
inline void GrStrokeRect(const Rectangle &r)
	{ Port::port->StrokeRect(Port::port->penink, Port::port->pensize, r); }
inline void GrEraseRect(const Rectangle &r)
	{ Port::port->FillRect(gInkWhite, r); }
inline void GrInvertRect(const Rectangle &r)
	{ Port::port->FillRect(gInkXor, r); }
inline void GrPaintRect(const Rectangle &r, Ink *ink)
	{ Port::port->FillRect(ink, r); }
inline void GrStrokeRoundRect(const Rectangle &r, const Point &dia)
	{ Port::port->StrokeRRect(Port::port->penink, Port::port->pensize, r, dia); }
inline void GrFillRoundRect(const Rectangle &r, const Point &dia)
	{ Port::port->FillRRect(Port::port->fillink, r, dia); }
inline void GrEraseRoundRect(const Rectangle &r, const Point &dia)
	{ Port::port->FillRRect(gInkWhite, r, dia); }
inline void GrInvertRoundRect(const Rectangle &r, const Point &dia)
	{ Port::port->FillRRect(gInkXor, r, dia); }
inline void GrPaintRoundRect(const Rectangle &r, const Point &dia, Ink *ink)
	{ Port::port->FillRRect(ink, r, dia); }
inline void GrStrokeOval(const Rectangle &r)
	{ Port::port->StrokeOval(Port::port->penink, Port::port->pensize, r); }
inline void GrFillOval(const Rectangle &r)
	{ Port::port->FillOval(Port::port->fillink, r); }
inline void GrEraseOval(const Rectangle &r)
	{ Port::port->FillOval(gInkWhite, r); }
inline void GrInvertOval(const Rectangle &r)
	{ Port::port->FillOval(gInkXor, r); }
inline void GrPaintOval(const Rectangle &r, Ink *ink)
	{ Port::port->FillOval(ink, r); }
inline void GrStrokeWedge(const Rectangle &r, int s, int e)
	{ Port::port->StrokeWedge(Port::port->penink, Port::port->pensize, Port::port->pencap, r, s, e); }
inline void GrFillWedge(const Rectangle &r, int s, int e)
	{ Port::port->FillWedge(Port::port->fillink, r, s, e); }
inline void GrEraseWedge(const Rectangle &r, int s, int e)
	{ Port::port->FillWedge(gInkWhite, r, s, e); }
inline void GrInvertWedge(const Rectangle &r, int s, int e)
	{ Port::port->FillWedge(gInkXor, r, s, e); }
inline void GrPaintWedge(const Rectangle &r, int s, int e, Ink *ink)
	{ Port::port->FillWedge(ink, r, s, e); }
inline void GrShowBitMap(const Rectangle &r, Bitmap *bmp)
	{ Port::port->ShowBitmap(Port::port->fillink, r, bmp); }
inline void GrPaintBitMap(const Rectangle &r, Bitmap *bmp, Ink *ink)
	{ Port::port->ShowBitmap(ink, r, bmp); }
inline void GrInvertBitMap(const Rectangle &r, Bitmap *bmp)
	{ Port::port->ShowBitmap(gInkXor, r, bmp); }
inline void GrStrokePolygon(const Point &at, Point *pts, int npts, GrPolyType t)
	{ Port::port->StrokePolygon(at, Port::port->penink, pts, npts, t,
		Port::port->pensize, Port::port->pencap); }
inline void GrFillPolygon(const Point &at, Point *pts, int npts, GrPolyType t)
	{ Port::port->FillPolygon(at, Port::port->fillink, pts, npts, t); }
inline void GrErasePolygon(const Point &at, Point *pts, int npts, GrPolyType t)
	{ Port::port->FillPolygon(at, gInkWhite, pts, npts, t); }
inline void GrInvertPolygon(const Point &at, Point *pts, int npts, GrPolyType t)
	{ Port::port->FillPolygon(at, gInkXor, pts, npts, t); }
inline void GrPaintPolygon(const Point &at, Ink *ink, Point *pts, int npts, GrPolyType t)
	{ Port::port->FillPolygon(at, ink, pts, npts, t); }
inline void GrSetFont(Font *fd)
	{ Port::port->SetFont(fd); }
inline Font *GrGetFont()
	{ return Port::port->GetFont(); }
inline void GrSetFamily(GrFont f)
	{ Port::port->SetFamily(f); }
inline void GrSetSize(int s)
	{ Port::port->SetSize(s); }
inline void GrSetFace(GrFace f)
	{ Port::port->SetFace(f); }
inline void GrSetTextInk(Ink *tink)
	{ Port::port->SetTextInk(tink); }
inline void GrSetTextNormal()
	{ Port::port->SetTextNormal(); }
inline Ink *GrGetTextInk()
	{ return Port::port->GetTextInk(); }
inline void GrTextMoveto(Point p)
	{ Port::port->TextMoveto(p); }
inline void GrTextAdvance(int h)
	{ Port::port->TextHMoveby(h); }
inline const Point &GrGetTextPos()
	{ return Port::port->GetTextPos(); }
inline int GrShowChar(Font *fdp, Ink *ink, const Point &pos, Rune c)
	{ return Port::port->ShowChar(fdp, ink, pos, c); }
inline void GrDrawChar(Rune c)
	{ Port::port->DrawChar(c); }
inline int GrShowString(Font *fd, Ink *ink, const Point &pos, byte *text, int l)
	{ return Port::port->ShowString(fd, ink, pos, text, l); }
inline void GrDrawString(byte *s, int l)
	{ Port::port->DrawString(s, l); }
inline void GrShowPicture(const Rectangle &r, Picture *pic)
	{ Port::port->ShowPicture(r, pic); }
inline GrCursor GrSetCursor(GrCursor c)
	{ return Port::port->SetCursor(c); }
inline GrCursor GrGetCursor()
	{ return Port::port->GetCursor(); }
inline GrCursor GrSetWaitCursor(unsigned int d, GrCursor c)
	{ return Port::port->SetWaitCursor(d, c); }
inline void GrGiveHint(int n, int l, void *v)
	{ Port::port->GiveHint(n, l, v); }
inline bool GrHasColor()
	{ return Port::port->HasColor(); }

//---- ImageCache --------------------------------------------------------------

class ImageCache {
public:
	Bitmap *b;
	Rectangle vr, r;
	bool valid;
public:
	ImageCache()
		{ b= 0; valid= FALSE; }
	~ImageCache()
		{ SafeDelete(b); }
	bool Open(const Rectangle &rr)
		{ return Port::port->DevImageCacheBegin(this, rr); }
	void Close()
		{ Port::port->DevImageCacheEnd(this); }
	void Invalidate()
		{ valid= FALSE; }
};

//---- Show wait cursor --------------------------------------------------------

class GrShowWaitCursor {
	GrCursor oldCursor;
public:
	GrShowWaitCursor()
		{ oldCursor= GrSetWaitCursor(); }
	~GrShowWaitCursor()
		{ GrSetCursor(oldCursor); }
};

#endif
